/*
 * readBuffer.c
 *
 *  Created on: 2012. 4. 16.
 *      Author: jphong
 */
#include	<stdio.h>
#include	<stdlib.h>
#include	<unistd.h>
#include	<ctype.h>
#include	<errno.h>
#include	<sys/types.h>
#include	<string.h>
#include	<sys/uio.h>
#include	"readBuffer.h"

void
initRbuf(ReadBuffer *rbuf) {
	rbuf->count = 0;
	rbuf->rear = rbuf->front = 0;
}

/* Create ReadBuffer with buffer length with bufsize
 * 		rbuf->buf:	start of buffer
 * 		rbuf->bufsize:	buffer size
 * 		rbuf->rear: index of buf to get string from the buffer, i.e. buf[rear]
 * 		rbug->front: index of buf to put on the buffer (first empty space)
 * 		rbuf->count: # of characters fill in buffer
 * 	Returns:
 * 		pointer to ReadBuffer if successful allocation
 * 		NULL if malloc() failed
 */
ReadBuffer *
createRbuf(int bufsize){
	ReadBuffer *rbuf;

	if ( 	((rbuf = (ReadBuffer *) malloc (sizeof(ReadBuffer))) != NULL) &&
			((rbuf->buf = (char *) malloc((size_t) bufsize)) !=NULL)
			) {
		;
	} else
		return (NULL);	// Not enough memory

	// Initialize the readBuffer node
	initRbuf(rbuf);
	rbuf->bufsize = bufsize;

	return (rbuf);	// returns pointer to the ReadBuffer
}

void
destroyRbuf(ReadBuffer *rbuf)
{
	if (rbuf != NULL) {
		free(rbuf->buf);
		free(rbuf);
	}
}

// Read from fd and append it to readBuffer
ssize_t
readBuf(ReadBuffer *rbuf, int fd)
{
	ssize_t	n;

	struct iovec iov[2];
	int empty, iov_cnt;

	empty = rbuf->bufsize - rbuf->count;
	iov[0].iov_base = rbuf->buf + rbuf->front;
	if ( (rbuf->front + empty) > rbuf->bufsize ) {	// empty space wrap around
		iov[0].iov_len = rbuf->bufsize - rbuf->front;
		iov[1].iov_base = rbuf->buf;
		iov[1].iov_len = empty - iov[0].iov_len;
		iov_cnt = 2;
	} else {
		iov[0].iov_len = empty;
		iov_cnt = 1;
	}

again:
	if ( (n = readv(fd, iov, iov_cnt)) < 0 ) {
		if (errno == EINTR)
			goto again;
		return(-1);
	} else if (n == 0 ) {
			return (0);
	}
	(rbuf->count) += n;
	(rbuf->front) = (rbuf->front + n) % rbuf->bufsize;

	return (n);
}

/*
 * Get a character from Rbuf
 * 	Returns:	0 if no more character
 */
unsigned char
getChar(ReadBuffer *rbuf)
{
	char	c;

	if ( rbuf->count <= 0) {
		return ('\0');
	}
	c = (rbuf->buf)[rbuf->rear];
	rbuf->rear = (rbuf->rear + 1) % rbuf->bufsize;
	(rbuf->count)--;
	return (c);
}

/*
 * Put a character to Rbuf
 *  Returns:	0 if no more space for putting a character
 */
unsigned char
ungetChar(ReadBuffer *rbuf, unsigned char c)
{
	if (rbuf->count == rbuf->bufsize) {
		return ('\0');
	}
	rbuf->rear = (rbuf->rear - 1) % rbuf->bufsize;
	(rbuf->buf)[rbuf->rear] = c;
	(rbuf->count)++;
	return (c);
}


#define	add(x, y) (((x) + (y)) % (rbuf->bufsize))
#define	inc(x)		(((x) + 1) % rbuf->bufsize)
/*
 * Get string terminated with 'suffix' string from ReadBuffer
 * 	(Reentrant and nonblocking function)
 * 	Returns:	pointer to the string	if found (string copied  into 'str')
 * 				NULL		if not found	(does not blocked)
 */
char *
getSuffix(ReadBuffer *rbuf, char *str, ssize_t strsize, char *suffix)
{
	int 	suffix_len;
	int		count, rear, i;
	char	*buf, *s;

	if (rbuf->count == 0)
		return (0);

	suffix_len = strlen(suffix);
	count = rbuf->count;
	rear = rbuf->rear;
	buf = rbuf->buf;

	for ( s = str; (count >= suffix_len) && (s + suffix_len <= str + strsize);
			*s++ = buf[rear], count--, rear = (rear+1) % rbuf->bufsize) {
		// compare to suffix
		for (i=0; i < suffix_len; i++) {
			if (buf[(rear + i) % rbuf->bufsize] != suffix[i])	// Not equal
				break;
		}
		if ( i == suffix_len) {	// Found
			// Found
			for (i=0; i < suffix_len; i++) { // Copy suffix
				*s++ = suffix[i];
			}
			*s = '\0';

			// advance ReadBuffer
			rbuf->count = count - suffix_len;
			rbuf->rear = (rear + suffix_len) % rbuf->bufsize;
			return (str);
		}
	}
	return (NULL); 	// Not found. Try later
}

/* Get string of length 'len' from ReadBuffer
 * 	Returns:	point to string 'str'
 * 				NULL		if not enough in ReadBuffer
 */
char *
getString(ReadBuffer *rbuf, char *str, ssize_t len)
{
	ssize_t		len1;

	if (len > rbuf->count)
		return (NULL);		// not enough

	if ( (len1 = rbuf->rear + len -  rbuf->bufsize ) > 0) {
		memcpy(str, rbuf->buf + rbuf->rear, len - len1);
		memcpy(str + len - len1, rbuf->buf, len1);
	} else
		memcpy(str, rbuf->buf + rbuf->rear, len);
	*(str + len) = '\0';		// NULL-terminated
	rbuf->count -= len;
	rbuf->rear = (rbuf->rear + len) % rbuf->bufsize;

	return (str);
}

/*
 * Get a line terminated with <LF>, <CRLF>, <CRLF><CRLF> from ReadBuffer
 * 	(Reentrant and nonblocking function)
 * 	Returns:	pointer to the line	if found (line copied  into buf)
 * 				NULL		if not found	(does not blocked)
 */
char *
getLine(ReadBuffer *rbuf, char *buf, ssize_t bufsize)
{
	return (getSuffix(rbuf, buf, bufsize, "\n"));
}

char*
getCRLF(ReadBuffer *rbuf, char *buf, ssize_t bufsize)
{
	return (getSuffix(rbuf, buf, bufsize, "\r\n"));
}

char *
getMessage(ReadBuffer *rbuf, char *buf, ssize_t bufsize)
{
	return (getSuffix(rbuf, buf, bufsize, "\r\n\r\n"));
}




char* space_remover(char* dst, char* src, size_t srclen) {

	size_t n;
	char* end = src;

	for (n = 1; n <= srclen; n++) {
		if ((*src == ' ') || (*src == '\n') || (*src == '\r')) {
			src++;
			continue;
		} else {
			while ((*src != ' ') && (*src != '\n') && (*src != '\r')
					&& (*src != 0)) {
				*dst++ = *src;
				src++;
				end = src;
				n++;
			}
			*dst = 0;
			break;
		}
	}
	return end;
}

char* space_remover2(char* src, size_t srclen) {

	size_t n;
	char* start = src;

	for (n = 1; n <= srclen; n++) {
		if ((*src == ' ') || (*src == '\n') || (*src == '\r')) {
			src++;
			continue;
		} else {
			return src;
		}
	}
	return start;
}
